<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.13"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Acconeer API: Envelope Service</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="resize.js"></script>
<script type="text/javascript" src="navtreedata.js"></script>
<script type="text/javascript" src="navtree.js"></script>
<script type="text/javascript">
  $(document).ready(initResizable);
</script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr style="height: 56px;">
  <td id="projectalign" style="padding-left: 0.5em;">
   <div id="projectname">Acconeer API
   </div>
  </td>
 </tr>
 </tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.13 -->
<script type="text/javascript">
var searchBox = new SearchBox("searchBox", "search",false,'Search');
</script>
<script type="text/javascript" src="menudata.js"></script>
<script type="text/javascript" src="menu.js"></script>
<script type="text/javascript">
$(function() {
  initMenu('',true,false,'search.php','Search');
  $(document).ready(function() { init_search(); });
});
</script>
<div id="main-nav"></div>
</div><!-- top -->
<div id="side-nav" class="ui-resizable side-nav-resizable">
  <div id="nav-tree">
    <div id="nav-tree-contents">
      <div id="nav-sync" class="sync"></div>
    </div>
  </div>
  <div id="splitbar" style="-moz-user-select:none;" 
       class="ui-resizable-handle">
  </div>
</div>
<script type="text/javascript">
$(document).ready(function(){initNavTree('envelope.html','');});
</script>
<div id="doc-content">
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
     onmouseover="return searchBox.OnSearchSelectShow()"
     onmouseout="return searchBox.OnSearchSelectHide()"
     onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>

<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0" 
        name="MSearchResults" id="MSearchResults">
</iframe>
</div>

<div class="header">
  <div class="headertitle">
<div class="title">Envelope Service </div>  </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p>The Envelope Service is one of four services that provides an interface for reading out the radar signal from the Acconeer A111 sensor. The data returned from the Envelope service is typically further processed and can be used in different types of algorithms such as distance measurement algorithms, motion detection algorithms, and object positioning algorithms. In use cases where low computation complexity is important, and the exact location of objects is less important you may consider using the power bins service instead of the Envelope service. Advanced users that needs phase information for detecting very small variations in distance will probably prefer the IQ data service instead of the envelop service. Users which are interested in detection of any movement, small or large, occurring in front of the sensor can instead use our sparse service.</p>
<div class="image">
<img src="RSS_stack.png" alt="RSS_stack.png"/>
</div>
<p>Acconeer also provide several easy to use detectors that are implemented on top of the basic data services. The detectors provide an interface for higher level tasks like distance measurements, motion detection etc.</p>
<p>Acconeer provides an example of how to use the Envelope service: <a class="el" href="example__service__envelope_8c.html">example_service_envelope.c</a></p>
<p>For more details on the Envelope data it is recommended to use our exploration tool. Check it out on <a href="https://github.com/acconeer/acconeer-python-exploration">github</a>, <a href="https://github.com/acconeer/acconeer-python-exploration">https://github.com/acconeer/acconeer-python-exploration</a>.</p>
<h2>Disclaimer</h2>
<p>Profile 3-5 will not have optimal performance using A111 with batch number 10467, 10457 or 10178 (also when mounted on XR111 and XR112). XM112 and XM122 are not affected since they have A111 from other batches.</p>
<h1>Setting up the Service</h1>
<h2>Initializing the System</h2>
<p>The Radar System Software (RSS) must be activated before any other calls are done. The activation requires a pointer to an <a class="el" href="structacc__hal__t.html" title="This struct contains the information about the sensor integration that RSS needs. ...">acc_hal_t</a> struct which contains information on the hardware integration and function pointers to hardware driver functions that are needed by RSS. See chapter 4 in the document “HAL Integration User Guide” for more information on how to integrate to the driver layer and populate the hal struct.</p>
<p>In Acconeer’s example integration towards STM32 and the drivers generated by the STM32Cube tool, there is a function acc_hal_integration_get_implementation to obtain the hal struct.</p>
<div class="fragment"><div class="line"><a class="code" href="structacc__hal__t.html">acc_hal_t</a> hal = <a class="code" href="acc__hal__integration_8h.html#a8b93eb4abdb9ad75250ca6404e0b412d">acc_hal_integration_get_implementation</a>();</div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (!<a class="code" href="group__RSS.html#ga478a45b4920777d3d4fc0f5fc8d05b58">acc_rss_activate</a>(&amp;hal))</div><div class="line">{</div><div class="line">        <span class="comment">/* Handle error */</span></div><div class="line">}</div></div><!-- fragment --><p>The corresponding code looks slightly different in software packages for the Raspberry Pi and other software packages from Acconeer where peripheral drivers for the host are included. The driver layer is first initialized by calling acc_driver_hal_init. The hal struct is then obtained with the function acc_driver_hal_get_implementation.</p>
<div class="fragment"><div class="line"><span class="keywordflow">if</span> (!acc_driver_hal_init())</div><div class="line">{</div><div class="line">        <span class="comment">/* Handle error */</span></div><div class="line">}</div><div class="line"></div><div class="line"><a class="code" href="structacc__hal__t.html">acc_hal_t</a> hal = acc_driver_hal_get_implementation();</div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (!<a class="code" href="group__RSS.html#ga478a45b4920777d3d4fc0f5fc8d05b58">acc_rss_activate</a>(&amp;hal))</div><div class="line">{</div><div class="line">        <span class="comment">/* Handle error */</span></div><div class="line">}</div></div><!-- fragment --><h2>Service API</h2>
<p>All services in the Acconeer API are created and activated in two distinct steps. In the first creation step the configuration settings are evaluated and all necessary resources are allocated. If there is some error in the configuration or if there are not enough resources in the system to run the service, the creation step will fail. However, when the creation is successful you can be sure that the second activation step will not fail due to any configuration or resource issues. When the service is activated the radar is activated and can start producing data.</p>
<h2>Envelope Service Configuration</h2>
<p>Before the Envelope service can be created and activated, we must prepare a service configuration. First a configuration is created.</p>
<div class="fragment"><div class="line"><a class="code" href="group__Generic.html#ga3659144b760468217ed4cb1fc3447330">acc_service_configuration_t</a> envelope_configuration = <a class="code" href="group__Envelope.html#ga1961bbe0a32fa9f1367fec2cc4b8b2d9">acc_service_envelope_configuration_create</a>();</div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (envelope_configuration == NULL)</div><div class="line">{</div><div class="line">        <span class="comment">/* Handle error */</span></div><div class="line">}</div></div><!-- fragment --><p>The newly created service configuration contains default settings for all configuration parameters and can be passed directly to the acc_service_create function. However, in most scenarios there is a need to change at least some of the configuration parameters. See <a class="el" href="acc__service__envelope_8h.html">acc_service_envelope.h</a> and <a class="el" href="acc__base__configuration_8h.html">acc_base_configuration.h</a> for a complete description of configuration parameters.</p>
<h3>Profiles</h3>
<p>The services and detectors support profiles with different configuration of emission in the sensor. The different profiles provide an option to configure the wavelet length and optimize on either depth resolution or radar loop gain. More information regarding profiles can be read in the <a href="https://acconeer-python-exploration.readthedocs.io/en/latest/sensor_introduction.html">sensor introduction document</a>, <a href="https://acconeer-python-exploration.readthedocs.io/en/latest/sensor_introduction.html">https://acconeer-python-exploration.readthedocs.io/en/latest/sensor_introduction.html</a>.</p>
<div class="image">
<img src="fig_distance_resolution.png" alt="fig_distance_resolution.png"/>
</div>
<p>The figure above shows the envelope signal of the same objects with two different profiles, one with short wavelet and one with longer.</p>
<p>The Envelope service supports 5 different profiles which are defined in <a class="el" href="acc__service_8h.html">acc_service.h</a>. Profile 1 has the shortest wavelet and should be used in applications which aim to see multiple objects or with short distance to the object. Profiles with higher numbers have longer wavelets and are more suitable to use in applications which aim to see objects with weak reflection or objects further away from the sensor. The highest profiles, 4 and 5, are optimized for maximum radar loop gain which leads to lower precision in the distance estimate.</p>
<p>Profiles can be configured by the application by using a set function in the service api. The default profile is ACC_SERVICE_PROFILE_2.</p>
<div class="fragment"><div class="line"><span class="keywordtype">void</span> <a class="code" href="group__Generic.html#gad3791b1f05c041be251aedbbf6e4756f">acc_service_profile_set</a>(<a class="code" href="group__Generic.html#ga3659144b760468217ed4cb1fc3447330">acc_service_configuration_t</a> service_configuration,</div><div class="line">                             <a class="code" href="group__Generic.html#gaa281da2c8fcd709b60cfdfe2b75b888a">acc_service_profile_t</a>       profile);</div></div><!-- fragment --><h3>Repetition Mode</h3>
<p>RSS supports two different repetition modes which configure the control flow of the sensor when it's producing data. In both modes, the application initiates the data transfer from the sensor and is responsible to keep the timing by fetching data from the service. The repetition modes are called on_demand and streaming and the default mode is on_demand.</p>
<p>Repetition mode on_demand lets the application decide when the sensor produces data. This mode is recommended to be used if the application is not dependent of a fixed update rate and it's more important for the application to control the timing. An example could be if the application requests data at irregular time or with low frequency and it's more important to enable low power consumption. Repetition mode on_demand should also be used if the application set a length which requires stitching or want to use power save mode off.</p>
<div class="fragment"><div class="line"><span class="keywordtype">void</span> <a class="code" href="group__Base.html#gaf0300d0b678002ee5298c6ce0af04cf9">acc_base_configuration_repetition_mode_on_demand_set</a>(<a class="code" href="group__Base.html#gacaedd5eecda28ac996abb8ff9e872c30">acc_base_configuration_t</a> configuration);</div></div><!-- fragment --><p>Repetition mode streaming configures the sensor to produce data based on a hardware timer which is very accurate. It is recommended to use repetition mode streaming if the application requires very accurate timing. An example could be if the data should be processed with a fft. This mode can not be used it the application set a length which requires stitching.</p>
<div class="fragment"><div class="line"><span class="keywordtype">void</span> <a class="code" href="group__Base.html#ga724423ab3347405e165a2f844eb2924d">acc_base_configuration_repetition_mode_streaming_set</a>(<a class="code" href="group__Base.html#gacaedd5eecda28ac996abb8ff9e872c30">acc_base_configuration_t</a> configuration, <span class="keywordtype">float</span> update_rate);</div></div><!-- fragment --><h2>Creating Service</h2>
<p>After the Envelope configuration has been prepared and populated with desired configuration parameters, the actual Envelope service instance must be created. During the creation step all configuration parameters are validated and the resources needed by RSS are reserved. This means that if the creation step is successful, we can be sure that it is possible to activate the service and get data from the sensor (unless there is some unexpected hardware error).</p>
<div class="fragment"><div class="line"><a class="code" href="group__Generic.html#gac31f87097f46e587c8d54fb0406f62d4">acc_service_handle_t</a> handle = <a class="code" href="group__Generic.html#ga165f40004fae21f84757a839f7253db0">acc_service_create</a>(envelope_configuration);</div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (handle == NULL)</div><div class="line">{</div><div class="line">        <span class="comment">/* Handle error */</span></div><div class="line">}</div></div><!-- fragment --><p>During service create, the service run a calibration sequence on the sensor. The calibration is used once at create and can be used until the service is destroyed. A new calibration is needed if the environment is changed, such as deviation in temperature.</p>
<p>If the service handle returned from acc_service_create is equal to NULL, then some setting in the configuration made it impossible for the system to create the service. One common reason is that the requested sweep length is too long or if the calibration fail, but in general, looking for error messages in the log is the best way to find out why a service creation failed.</p>
<p>When the service has been created it is possible to get the actual number of samples (data_length) we will get for each result. This value can be useful when allocating buffers for storing the Envelope data.</p>
<div class="fragment"><div class="line"><a class="code" href="structacc__service__envelope__metadata__t.html">acc_service_envelope_metadata_t</a> envelope_metadata;</div><div class="line"><a class="code" href="group__Envelope.html#ga6dcf91e972ace258485cfa6020c3bb9c">acc_service_envelope_get_metadata</a>(handle, &amp;envelope_metadata);</div><div class="line"></div><div class="line">uint16_t data[envelope_metadata.<a class="code" href="structacc__service__envelope__metadata__t.html#a5be240b186b7c46eeef835a13b899aad">data_length</a>];</div></div><!-- fragment --><p>It is now also possible to activate the service. This means that the radar sensor may start to produce data</p>
<div class="fragment"><div class="line"><span class="keywordflow">if</span> (!<a class="code" href="group__Generic.html#ga35f20ca785726b4c1c7aacf46c46cf39">acc_service_activate</a>(handle))</div><div class="line">{</div><div class="line">        <span class="comment">/* Handle error */</span></div><div class="line">}</div></div><!-- fragment --><h2>Reading Envelope Data from the Sensor</h2>
<p>Envelope data is read from the sensor by a call to the function acc_service_envelope_get_next. This function blocks until the next sweep arrives from the sensor and the result is available in envelope_data.</p>
<div class="fragment"><div class="line">uint16_t                           data[envelope_metadata.<a class="code" href="structacc__service__envelope__metadata__t.html#a5be240b186b7c46eeef835a13b899aad">data_length</a>];</div><div class="line"><a class="code" href="structacc__service__envelope__result__info__t.html">acc_service_envelope_result_info_t</a> result_info;</div><div class="line"></div><div class="line"><span class="keywordflow">for</span> (<span class="keywordtype">int</span> i = 0; i &lt; 10; i++)</div><div class="line">{</div><div class="line">        <span class="keywordflow">if</span> (!<a class="code" href="group__Envelope.html#gaefee7fa19c46d279460a58483ce0b8a1">acc_service_envelope_get_next</a>(handle, data, envelope_metadata.<a class="code" href="structacc__service__envelope__metadata__t.html#a5be240b186b7c46eeef835a13b899aad">data_length</a>, &amp;result_info))</div><div class="line">        {</div><div class="line">                <span class="comment">/* Handle error */</span></div><div class="line">        }</div><div class="line">}</div></div><!-- fragment --><h2>Deactivating and Destroying the Service</h2>
<p>Call the acc_service_deactivate function to stop measurements.</p>
<div class="fragment"><div class="line"><span class="keywordflow">if</span> (!<a class="code" href="group__Generic.html#gaa1b126a55a9defe0d7baff5d7890435f">acc_service_deactivate</a>(handle))</div><div class="line">{</div><div class="line">        <span class="comment">/* Handle error */</span></div><div class="line">}</div></div><!-- fragment --><p>After the service has been deactivated it can be activated again to resume measurements or it can be destroyed to free up the resources associated with the service handle.</p>
<div class="fragment"><div class="line"><a class="code" href="group__Generic.html#gad7cc3154b0227e63d18b11aa672de3af">acc_service_destroy</a>(&amp;handle);</div></div><!-- fragment --><p>Finally, call acc_rss_deactivate when the application doesn’t need to access the Radar System Software anymore. This releases any remaining resources allocated in RSS.</p>
<div class="fragment"><div class="line"><a class="code" href="group__RSS.html#ga5221ed13d3d7aff540420aacfe55b5e2">acc_rss_deactivate</a>();</div></div><!-- fragment --><h1>How to Interpret the Envelope Data</h1>
<p>The Envelope data should be interpreted as a single one-dimensional array, where each array element represents the amplitude of the reflected signal from objects at a particular radial distance from the sensor.</p>
<div class="image">
<img src="envelope.png" alt="envelope.png"/>
</div>
<p>Assume that you have a setup with two objects like in the figure above. When plotting the Envelope data recorded using profile 1, which is optimized for maximum depth resolution, you will get a graph similar to the one below.</p>
<div class="image">
<img src="envelope_profile_1.png" alt="envelope_profile_1.png"/>
</div>
<p>When a profile is choosen to improve radar loop gain, the radar sends out more energy, and the receiver has a higher gain setting which leads to a higher amplitude in the received signal. The internal filter parameters are also different which gives a smoother signal where noise and fine details have been removed. The graph below shows the same two objects as before but with profile 2 enabled.</p>
<div class="image">
<img src="envelope_profile_2.png" alt="envelope_profile_2.png"/>
</div>
<h2>Envelope Metadata</h2>
<p>In addition to the array with Envelope data samples, a metadata data structure provides side information that can be useful when interpreting the Envelope data. This metadata can be retrieved after creating the service. It will not change during operation, so it is only needed to be retrieved once for the created service.</p>
<div class="fragment"><div class="line"><a class="code" href="structacc__service__envelope__metadata__t.html">acc_service_envelope_metadata_t</a> envelope_metadata;</div><div class="line"><a class="code" href="group__Envelope.html#ga6dcf91e972ace258485cfa6020c3bb9c">acc_service_envelope_get_metadata</a>(handle, &amp;envelope_metadata);</div></div><!-- fragment --><p>The most important member variable in the meta data structure is data_length which holds the length of the Envelope data array. For other member variables see <a class="el" href="structacc__service__envelope__metadata__t.html" title="Metadata for the envelope service. ">acc_service_envelope_metadata_t</a>.</p>
<h2>Envelope Result Info</h2>
<p>Result info is another kind of metadata which might change for each retrieved result. Result info is provided at the same time as the resulting array, either when calling get_next() or when a callback is triggered.</p>
<div class="fragment"><div class="line"><a class="code" href="structacc__service__envelope__result__info__t.html">acc_service_envelope_result_info_t</a> result_info;</div><div class="line"><a class="code" href="group__Envelope.html#gaefee7fa19c46d279460a58483ce0b8a1">acc_service_envelope_get_next</a>(handle, data, data_length, &amp;result_info);</div></div><!-- fragment --><p>The most important member variable is the sensor_communication_error which indicates whether a sensor communication has occurred. For other member variables see <a class="el" href="structacc__service__envelope__result__info__t.html" title="Metadata for each result provided by the envelope service. ">acc_service_envelope_result_info_t</a></p>
<h1>Examples</h1>
<h2>Simple Distance Algorithm Example</h2>
<p>In this example we will implement a simple distance algorithm that finds the distance to the strongest reflecting object by finding the highest peak in the Envelope data. We start by writing a function to find the index for the value in the Envelope data array with the highest amplitude.</p>
<div class="fragment"><div class="line"><span class="keywordtype">int</span> peak_index(uint16_t data[], uint16_t data_length)</div><div class="line">{</div><div class="line">    uint16_t max = 0;</div><div class="line">    <span class="keywordtype">int</span> peak_idx = 0;</div><div class="line">    <span class="keywordflow">for</span> (<span class="keywordtype">int</span> i = 0 ; i&lt;data_length ; i++)</div><div class="line">    {</div><div class="line">        <span class="keywordflow">if</span> (data[i] &gt; max )</div><div class="line">        {</div><div class="line">            max = data[i];</div><div class="line">            peak_idx = i;</div><div class="line">        }</div><div class="line">    }</div><div class="line">    <span class="keywordflow">return</span> peak_idx;</div><div class="line">}</div></div><!-- fragment --><p>By using information on start and length in the meta data structure we can transform the index to a distance. To avoid measuring the distance to some peak in the background noise when there is no object in front of the sensor we define an amplitude threshold that must be exceeded in order to write out that we found a distance.</p>
<div class="fragment"><div class="line"><span class="keywordtype">int</span> peak_idx = peak_index(envelope_data, envelope_metadata.<a class="code" href="structacc__service__envelope__metadata__t.html#a5be240b186b7c46eeef835a13b899aad">data_length</a>);</div><div class="line">unint16_t min_amplitude = 1000;</div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (envelope_data[peak_idx] &gt; min_amplitude)</div><div class="line">{</div><div class="line">   <span class="keywordtype">float</span> dist =  envelope_metadata.<a class="code" href="structacc__service__envelope__metadata__t.html#a2a0d6b22f6460d85949de6272020cf61">start_m</a> + peak_idx *</div><div class="line">                 envelope_metadata.<a class="code" href="structacc__service__envelope__metadata__t.html#a7a38689aafbce5b67f949e7a91ded741">step_length_m</a>;</div><div class="line">   printf (<span class="stringliteral">&quot;distance: %f, amplitude %u\n&quot;</span>, dist, envelope_data[peak_idx]);</div><div class="line">}</div><div class="line"><span class="keywordflow">else</span></div><div class="line">{</div><div class="line">   printf (<span class="stringliteral">&quot;amplitude under threshold\n&quot;</span>);</div><div class="line">}</div></div><!-- fragment --><h2>Direct Leakage Measurement</h2>
<p>In this example we will outline how to set up the service to do a direct leakage measurement. Note that only the configuration of the service is shown. Refer to previous chapters on how to create and activate the service and how to read out the service data.</p>
<div class="fragment"><div class="line"><a class="code" href="group__Generic.html#ga3659144b760468217ed4cb1fc3447330">acc_service_configuration_t</a> envelope_configuration = <a class="code" href="group__Envelope.html#ga1961bbe0a32fa9f1367fec2cc4b8b2d9">acc_service_envelope_configuration_create</a>();</div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (envelope_configuration == NULL)</div><div class="line">{</div><div class="line">        <span class="comment">/* Handle error */</span></div><div class="line">}</div><div class="line"></div><div class="line"><a class="code" href="group__Generic.html#ga628657526945463f111b3587a6551655">acc_service_maximize_signal_attenuation_set</a>(envelope_configuration, <span class="keyword">true</span>); <span class="comment">/* This is the main switch for performing direct leakage measurements */</span></div><div class="line"></div><div class="line">sweep_configuration = acc_service_get_sweep_configuration(envelope_configuration);</div><div class="line"><span class="keywordflow">if</span> (sweep_configuration == NULL)</div><div class="line">{</div><div class="line">        <span class="comment">/* Handle error */</span></div><div class="line">}</div><div class="line"></div><div class="line">acc_sweep_configuration_hw_accelerated_average_samples_set(sweep_configuration, 1); <span class="comment">/* Sampling each data point one time is suitable for this measurement */</span></div><div class="line">acc_sweep_configuration_receiver_gain_set(sweep_configuration, 0.09);               <span class="comment">/* Lower the receiver gain to not saturate the signal */</span></div><div class="line">acc_sweep_configuration_requested_range_set(sweep_configuration, -0.12, 0.12);      <span class="comment">/* Set the range where the direct leakage is visible */</span></div><div class="line"></div><div class="line"><span class="comment">/* Create, activate and read out the service data */</span></div></div><!-- fragment --> </div></div><!-- contents -->
</div><!-- doc-content -->
<!-- start footer part -->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
  <ul>
    <li class="navelem"><a class="el" href="md__home_ai_jenkins_workspace_sw-main_0D2_doc_user_guides_rss_user_guide_main.html">User guides</a></li>
    <li class="footer">Generated on Mon Dec 2 2019 09:40:46 for Acconeer API by
    <a href="http://www.doxygen.org/index.html">
    <img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.8.13 </li>
  </ul>
</div>
</body>
</html>
